﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using UnityEngine;

/// <summary>
/// HTTP返回内容
/// </summary>
public class HTTPResponse
{
    // 状态码
    private int statusCode;

    // 响应字节
    private byte[] responseBytes;

    // 错误内容
    private string error;

    /// <summary>
    /// 默认构造函数
    /// </summary>
    public HTTPResponse()
    {
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="content">响应内容</param>
    public HTTPResponse(byte[] content)
    {
        this.responseBytes = content;
    }

    /// <summary>
    /// 获取响应内容
    /// </summary>
    /// <returns>响应文本内容</returns>
    public string GetResponseText()
    {
        if (null == this.responseBytes)
        {
            return null;
        }
        return Encoding.UTF8.GetString(this.responseBytes);
    }

    /// <summary>
    /// 将响应内容存储到文件
    /// </summary>
    /// <param name="fileName">文件名称</param>
    public void SaveResponseToFile(string fileName)
    {
        if (null == this.responseBytes)
        {
            return;
        }
        // FIXME 路径跨平台问题
        string path = Path.Combine(Application.dataPath + "/StreamingAssets", fileName);
        FileStream fs = new FileStream(path, FileMode.Create);
        BinaryWriter writer = new BinaryWriter(fs);
        writer.Write(this.responseBytes);
        writer.Flush();
        writer.Close();
        fs.Close();
    }

    /// <summary>
    /// 获取状态码
    /// </summary>
    /// <value>状态码</value>
    public int StatusCode
    {
        set
        {
            this.statusCode = value;
        }
        get
        {
            return this.statusCode;
        }
    }

    /// <summary>
    /// 获取错误消息
    /// </summary>
    /// <value>错误消息</value>
    public string Error
    {
        set
        {
            this.error = value;
        }
        get
        {
            return this.error;
        }
    }
}

/// <summary>
/// Http请求
/// </summary>
public class HTTPRequest
{
    private string url;
    private int timeout;
    private Action<HTTPResponse> callback;
    private HttpWebRequest request;
    private string method;
    private string contentType;
    private KeyValuePair<string, int> proxy;
    protected int range = -1;

    // post内容
    private StringBuilder postBuilder;

    /// <summary>
    /// 错误代码
    /// </summary>
    public const int ERR_EXCEPTION = -1;

    /// <summary>
    /// 构造函数, 构造GET请求
    /// </summary>
    /// <param name="url">url地址</param>
    /// <param name="timeout">超时时间</param>
    /// <param name="callback">回调函数</param>
    public HTTPRequest(string url, string method, int timeout, Action<HTTPResponse> callback)
    {
        this.url = url;
        this.timeout = timeout;
        this.callback = callback;
        this.method = method.ToUpper();
    }

    /// <summary>
    /// 设置Post内容
    /// </summary>
    /// <param name="data">内容</param>
    public void SetPostData(string data)
    {
        if (postBuilder == null)
        {
            postBuilder = new StringBuilder(data.Length);
        }
        if (postBuilder.Length > 0)
        {
            postBuilder.Append("&");
        }
        postBuilder.Append(data);
    }

    /// <summary>
    /// 添加Post内容
    /// </summary>
    /// <param name="key">key值</param>
    /// <param name="value">value值</param>
    public void AddPostData(string key, string value)
    {
        if (postBuilder == null)
        {
            postBuilder = new StringBuilder();
        }
        if (postBuilder.Length > 0)
        {
            postBuilder.Append("&");
        }
        postBuilder.Append(key).Append("=").Append(UrlEncode(value));
    }

    /// <summary>
    /// 设置代理
    /// </summary>
    /// <param name="ip">ip地址</param>
    /// <param name="port">端口号</param>
    public void SetProxy(string ip, int port)
    {
        this.proxy = new KeyValuePair<string, int>(ip, port);
    }

    /// <summary>
    /// 设置ContentType
    /// </summary>
    /// <value>ContentType value</value>
    public string ContentType
    {
        set
        {
            this.contentType = value;
        }
    }

    /// <summary>
    /// 发动请求
    /// </summary>
    public void Start()
    {
        Debug.Log("Handle Http Request Start");
        this.request = WebRequest.Create(url) as HttpWebRequest;
        this.request.Timeout = timeout;
        this.request.Method = method;
        if (this.proxy.Key != null)
        {
            this.request.Proxy = new WebProxy(this.proxy.Key, this.proxy.Value);
        }
        if (this.contentType != null)
        {
            this.request.ContentType = this.contentType;
        }
        if (this.range != -1)
        {
            this.request.AddRange(this.range);
        }
        // POST写POST内容
        if (method.Equals("POST"))
        {
            WritePostData();
        }
        try
        {
            AsyncCallback callback = new AsyncCallback(OnResponse);
            this.request.BeginGetResponse(callback, null);
        }
        catch (Exception e)
        {
            CallBack(ERR_EXCEPTION, e.Message);
            if (request != null)
            {
                request.Abort();
            }
        }
    }

    /// <summary>
    /// 处理读取Response
    /// </summary>
    /// <param name="result">异步回到result</param>
    protected void OnResponse(IAsyncResult result)
    {
        //Debug.Log ("Handle Http Response");
        HttpWebResponse response = null;
        try
        {
            // 获取Response
            response = request.EndGetResponse(result) as HttpWebResponse;
            if (response.StatusCode == HttpStatusCode.OK)
            {
                if ("HEAD".Equals(method))
                {
                    // HEAD请求
                    long contentLength = response.ContentLength;
                    CallBack((int)response.StatusCode, contentLength + "");
                    return;
                }
                // 读取请求内容
                Stream responseStream = response.GetResponseStream();
                byte[] buff = new byte[2048];
                MemoryStream ms = new MemoryStream();
                int len = -1;
                while ((len = responseStream.Read(buff, 0, buff.Length)) > 0)
                {
                    ms.Write(buff, 0, len);
                }
                // 清理操作
                responseStream.Close();
                response.Close();
                request.Abort();
                // 调用回调
                CallBack((int)response.StatusCode, ms.ToArray());
            }
            else
            {
                CallBack((int)response.StatusCode, "");
            }
        }
        catch (Exception e)
        {
            CallBack(ERR_EXCEPTION, e.Message);
            if (request != null)
            {
                request.Abort();
            }
            if (response != null)
            {
                response.Close();
            }
        }
    }

    /// <summary>
    /// 回调
    /// </summary>
    /// <param name="code">编码</param>
    /// <param name="content">内容</param>
    private void CallBack(int code, string content)
    {
        Debug.LogFormat("Handle Http Callback, code:{0}", code);
        if (callback != null)
        {
            HTTPResponse response = new HTTPResponse();
            response.StatusCode = code;
            response.Error = content;
            callback(response);
        }
    }

    /// <summary>
    /// 回调
    /// </summary>
    /// <param name="code">编码</param>
    /// <param name="content">内容</param>
    private void CallBack(int code, byte[] content)
    {
        Debug.LogFormat("Handle Http Callback, code:{0}", code);
        if (callback != null)
        {
            HTTPResponse response = new HTTPResponse(content);
            response.StatusCode = code;
            callback(response);
        }
    }

    /// <summary>
    /// 写Post内容
    /// </summary>
    private void WritePostData()
    {
        if (null == postBuilder || postBuilder.Length <= 0)
        {
            return;
        }
        byte[] bytes = Encoding.UTF8.GetBytes(postBuilder.ToString());
        Stream stream = request.GetRequestStream();
        stream.Write(bytes, 0, bytes.Length);
        stream.Close();
    }

    /// <summary>
    /// URLEncode
    /// </summary>
    /// <returns>encode value</returns>
    /// <param name="value">要encode的值</param>
    private string UrlEncode(string value)
    {
        StringBuilder sb = new StringBuilder();
        byte[] byStr = System.Text.Encoding.UTF8.GetBytes(value);
        for (int i = 0; i < byStr.Length; i++)
        {
            sb.Append(@"%" + Convert.ToString(byStr[i], 16));
        }
        return (sb.ToString());
    }
}

/// <summary>
/// 文件下载
/// </summary>
public class HTTPDownLoad
{
    // 下载进度
    public float Progress
    {
        get;
        private set;
    }

    // 状态 0 正在下载 1 下载完成 -1 下载出错
    public int Status
    {
        get;
        private set;
    }

    // 错误信息
    public string Error
    {
        get;
        set;
    }

    // 总长度
    public long TotalLength
    {
        get;
        private set;
    }

    // 保存路径
    private string savePath;

    // url地址
    private string url;

    // 超时时间
    private int timeout;

    // 子线程
    private Thread thread;

    // 子线程是否停止标志
    private bool isStop;

    private Action<HTTPDownLoad> callback;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="url">url地址</param>
    /// <param name="timeout">超时时间</param>
    /// <param name="callback">回调函数</param>
    public HTTPDownLoad(string url, string savePath, int timeout, Action<HTTPDownLoad> callback)
    {
        this.savePath = savePath;
        this.url = url;
        this.timeout = timeout;
        this.callback = callback;
    }

    /// <summary>
    /// 开启下载
    /// </summary>
    public void DownLoad()
    {
        // 开启线程下载
        thread = new Thread(StartDownLoad);
        thread.IsBackground = true;
        thread.Start();
    }

    /// <summary>
    /// 开始下载
    /// </summary>
    private void StartDownLoad()
    {
        try
        {
            // 构建文件流
            FileStream fs = new FileStream(this.savePath, FileMode.OpenOrCreate, FileAccess.Write);
            // 文件当前长度
            long fileLength = fs.Length;
            // 文件总长度
            TotalLength = GetDownLoadFileSize();
            Debug.Log("fileLen:" + fileLength + "  max:" + TotalLength);
            if (fileLength < TotalLength)
            {
                // 没有下载完成
                fs.Seek(fileLength, SeekOrigin.Begin);
                // 发送请求开始下载
                HttpWebRequest request = WebRequest.Create(this.url) as HttpWebRequest;
                request.AddRange((int)fileLength);
                request.Timeout = this.timeout;
                // 读取文件内容
                Stream stream = request.GetResponse().GetResponseStream();
                if (stream.CanTimeout)
                {
                    stream.ReadTimeout = this.timeout;
                }
                byte[] buff = new byte[4096];
                int len = -1;
                while ((len = stream.Read(buff, 0, buff.Length)) > 0)
                {
                    if (isStop)
                    {
                        break;
                    }
                    fs.Write(buff, 0, len);
                    fileLength += len;
                    Progress = fileLength * 1.0f / TotalLength;
                }
                stream.Close();
                stream.Dispose();
            }
            else
            {
                Progress = 1;
            }
            fs.Close();
            fs.Dispose();
            // 标记下载完成
            if (Progress == 1)
            {
                Status = 1;
            }
            callback.Invoke(this);
        }
        catch (Exception e)
        {
            Error = e.Message;
            Status = -1;
        }
    }

    /// <summary>
    /// 获取下载的文件大小
    /// </summary>
    /// <returns>文件大小</returns>
    public long GetDownLoadFileSize()
    {
        HttpWebRequest request = WebRequest.Create(this.url) as HttpWebRequest;
        request.Method = "HEAD";
        request.Timeout = this.timeout;
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        return response.ContentLength;
    }

    /// <summary>
    /// 关闭下载
    /// </summary>
    public void Close()
    {
        this.isStop = true;
    }
}

public class NetworkManager
{
    /// <summary>
    /// 创建一个HTTP请求
    /// </summary>
    /// <param name="url">URL.</param>
    /// <param name="callback">Callback</param>
    public HTTPRequest CreateHTTPRequest(string url, string method, Action<string> callback)
    {
        HTTPRequest client = new HTTPRequest(url, method, 5000, (HTTPResponse response) =>
        {
            if (null != callback)
            {
                var t = response.GetResponseText();
                callback.Invoke(t);
            }
        });
        return client;
    }

    private int downFile = -1;

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="url">url</param>
    /// <param name="savePath">保存地址</param>
    /// <param name="callback">callback</param>
    public HTTPDownLoad DownLoadFile(string url, string savePath, Action<int, float, string> callback)
    {
        // 一次只允许下载一个文件
        if (downFile > 0)
        {
            callback.Invoke(-1, 0, "其他文件正在下载");
            return null;
        }
        downFile = 1;
        // 下载文件
        HTTPDownLoad download = new HTTPDownLoad(url, savePath, 5000, (dow) =>
        {// 回调函数
            callback.Invoke(dow.Status, dow.Progress, dow.Error);
            downFile = -1;
        });
        download.DownLoad();
        return download;
    }
}

//NetworkManager manager = new NetworkManager();
//var h = manager.CreateHTTPRequest("http://localhost:8080/DowVersion.txt", "GET", (s) =>
//{
//    debug.log("下载完成", s);
//});
//h.Start();
//var p = (PathConfig.Project + "/Assets/StreamingAssets/vioe.zip");
//debug.log(p);
//var df = manager.DownLoadFile("http://localhost:8080/ZIPversion.zip", p, (s, l, e) =>
//  {
//      debug.log(" 下载状态 ", s, " 进度 ", l, " 错误", e);
//
//  });